
function Page(options) {

    var me = this;
    this.name = 'page';
    this.router = null;
    var routes = {};
    this.groups = {'root': {}};
    this._haveCreate = false;
    this.m = {};

    window.onload = function () {
         me.onLoad();
    };
    window.unload = function () {
        me.onExit();
    };
    window.onkeydown = function (e) {


        var key = $g.event(e).keyCode;
        me.onKeyDown(key);

        //me.onKeyDown(e);
    };
};

Page.prototype = {

    constructor: Page,

    define : function (opt) {
        Page.call(this, opt); //this是个对象
        if (opt) {
            for (var property in opt) {
                this[property] = opt[property];
            }
        }
    },

    /** 内置函数  */
    _onLoad : function (){
        console.log('Page Base onLoad .....................');
    },
       
    //页面退出
    _onExit: function () {
        console.log('Page Base onExit  ................');
    },
    //事件处理
    _onKeyDown: function (key) {

        console.log('Page Base onKeyDown  ................');

        if($g.currentFocusRouter.isDirectDeal){
            $g.currentFocusRouter.callmodule.onKeyDown(key);
        }
        else
            $g.currentFocusRouter.go(key);

    }

};


function Component() {
    this.name = 'Component';
    var _html_ = '';
    // var _haveCreate = false;
    this.groups = {'root': {}};
    this._haveCreate = false;
    this.m = {};
    //路由信息
    var _routes = {};
    // this.groups = {'root': {}};
    this.router = null;
    //  var _currentFocusId = null;

};

Component.prototype = {

    constructor: Component,

    _currentFocusId : null,

    define : function (opt) {
        Component.call(this, opt); //this是个对象
        if (opt) {
            for (var property in opt) {
                this[property] = opt[property];
            }
        }

    },

    focus :function (id) {
       $g.getFocusRouter(this.name).focus(id);
    },

    onKeyDown: function (key) {
        $g.getFocusRouter(this.name).go(key);
    },


    onLoad: function () {
        console.log('load  module  -------  ' + this.name)

        if (!this._haveCreate)
            onCreate();

        this._currentFocusId = '';
        this.m._currentShowLine = 1;
        this.m._currentShowLineOffset = 0;


    },

    onCreate: function (componentName, that) {

       //cjn
       // if (this._haveCreate)
        //    return;

        console.log('component  onCreate -------------------------------')

        this.name = componentName;
        this.router = $g.createFocusRouter(componentName, that, false);
        this.router.routes = that._routes;
        this.router.groups = this.groups;
        this.router.groups.root.fn = [that._onFocus, that._onUnFocus, that._onSelect];

        this._haveCreate = true;

    },
    setFocusDiv : function(strId){
        this.router.focusDivId = strId;//为了焦点个性化
    },
    /**模块出去的路由处理*/

    onRouteOut: function (myid, otherModule, otherId) {

        /**记住自己从那个id出去的*/
        this._currentFocusId = myid;
    },

    /**其他模块不知道怎么跳入时，就会配置通配符*，由自己来处理*/
    onRouteIn: function (id, otherModule, otherId) {

        //可以设置默认的选中焦点
        $g.getFocusRouter(this.name).focus(this._currentFocusId);

    },

    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onFocus: function (id, router) {
        //var that = router.callmodule;
       // console.log('componse base  - _onFocus ---------------------');

 
    },
    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onUnFocus: function (id, router) {
        var that = router.callmodule; //实际就是this
        //console.log('componse base  - _onUnFocus ---------------------');

    },

    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onSelect: function (id, router) {
        var that = router.callmodule;
        console.log('componse base  - _onSelect ---------------------');

        // var url = that.config.links[that.routes[id].index];
        // setTimeout(function () {
        //    that.jumpOut(url, id);
        //}, 100);
    }


};

/**  Roller     */

/**
 * 
 *  类似菜单/toolbar 等数据多，显示位置少，需要对数据进行滚动，使用本基类
 * 
 *  在外部使用的时候，继承这个基类， create, update 
 *  外部配置Route和布局信息， 会返回调用下面回调函数：
 *  onRender : 在外部函数中处理数据渲染的问题，在更新数据，或者需要翻页的时候，会调用本函数
 *  onItemFocus/onItemUnFocus/onItemSelected :  返回焦点对象ID还有对应的数据索引index , 使用时不用考虑内部的各种事件，或者数据分区问题 
 *  内部数据说明： 
 *  _pageInfo 对象下面
    /**
     *  显示区 长度 
     *    viewLength  显示区长度,对应外部Element 数量
     *    viewIndex   当前显示位置
     *    viewMode    显示方向：1 水平， 2 垂直
     *      
     *  数据区：
     *   
     *   dataLength : 整个长度
     *   dataOffset : 开始显示数据索引
     * 
     *
 */

function Roller() {
    this.name = 'Roller';
    var _html_ = '';
    this._haveCreate = false;
 
    //路由信息
    var _routes = {};
    this.groups = {'root': {}};
    this.router = null;

};
Roller.prototype = {
    constructor: Roller,
    _currentFocusId : '',
    _haveCreate :false,
    step : 1,//滚动步进
    
    define : function (opt) {
        Roller.call(this, opt); //this是个对象
        if (opt) {
            for (var property in opt) {
                this[property] = opt[property];
            }
        }

    },

    focus :function (id) {
       $g.getFocusRouter(this.name).focus(id);


    },


    _go: function (key) {

        var p = this._pageInfo;

        //根据当前位置判读
        var r = $g.getFocusRouter(this.name);
        p.viewIndex = r.routes[r.currentFocus].index ;

        var focuseObj = null;
        switch (key) {
            case  $g.KeyCodes['ENTER']:
                //this._onSelect(selectObj);
                r.go(key);
                break;

            case $g.KeyCodes['LEFT']:
                //水平需要特殊处理
                if(p.viewMode == 'H' && p.viewIndex == 1 && p.dataOffset > 0){
                    p.dataOffset = Math.max(0,p.dataOffset -this.step);
                    return this.onRender(1,p.dataOffset);

                }else {

                    this._pageInfo.viewIndex = this._pageInfo.viewIndex -1;
                    r.go(key);
                }
                break; 
            case $g.KeyCodes['RIGHT']:
                //水平需要特殊处理
                if(p.viewMode == 'H' && p.viewIndex == p.viewLength && p.dataOffset + p.viewLength < p.dataLength){
                    p.dataOffset += this.step;
                    return this.onRender(2,p.dataOffset);

                }else {
                    this._pageInfo.viewIndex = this._pageInfo.viewIndex +1;
                    r.go(key);
                }
                break; 

            case $g.KeyCodes['UP']:

                if(p.viewMode == 'V' && p.viewIndex == 1 && p.dataOffset > 0){
                    p.dataOffset = Math.max(0,p.dataOffset -this.step);
                    return this.onRender(1,p.dataOffset);

                }else {

                    this._pageInfo.viewIndex = this._pageInfo.viewIndex -1;
                    r.go(key);
                }
                break; 
            case $g.KeyCodes['DOWN']:


                if(p.viewMode == 'V' && p.viewIndex == p.viewLength && p.dataOffset + p.viewLength < p.dataLength){
                    p.dataOffset += this.step;
                    return this.onRender(2,p.dataOffset);

                }else {
                    this._pageInfo.viewIndex = this._pageInfo.viewIndex +1;
                    r.go(key);
                }
                break; 

        }

    },

    setStep : function(val){
        this.step = val;
    },
    onKeyDown: function (key) {
        //需要根据Roller数据做事件处理，进行翻页，换行等操作
        this._go(key);
    },

    //内部初始化数据
    onLoad: function (data) {

        if(!this._haveCreate){
            console.log('Roller 对象没有创建！');
            return;
        }

        if(data == null) return;
        
        this._pageInfo.dataLength = data.length;
        this._pageInfo.dataOffset = 0;

        this.onRender(0,0);

    },

    //内部创建对象，主要是事件，回调，基本数据
    //componentName：用于登陆注册事件的对象名称
    //that this 指针
    //viewMode, 'H' 水平/ 'V' 垂直  viewLength 显示对象数量
    onCreate: function (componentName, that, viewMode, viewLength ) {

        this.name = componentName;
        //内部要重载处理事件
        this.router = $g.createFocusRouter(componentName, that, true);
        this.router.routes = that._routes;
        //router.groups = this.groups;
        this.router.groups = {root:{}};
        this.router.groups.root.fn = [this._onFocus, this._onUnFocus, this._onSelect];

        this._pageInfo.viewMode = viewMode;
        this._pageInfo.viewLength = viewLength;
        this._pageInfo.viewIndex = 0;

        this._currentFocusId = '';
        this._haveCreate = true;

    },
    /**模块出去的路由处理*/
    onRouteOut: function (myid, otherModule, otherId) {
        /**记住自己从那个id出去的*/
        this._currentFocusId = myid;
    },

    /**其他模块不知道怎么跳入时，就会配置通配符*，由自己来处理*/
    onRouteIn: function (id, otherModule, otherId) {
        //可以设置默认的选中焦点
        $g.getFocusRouter(this.name).focus(this._currentFocusId);

    },

    /** Item 被选中 */
    onItemSelect:function(id,index ){},

    /** Item 被Focus */
    onItemFocus:function(id,index ){},
    
    /** Item 被选中 */
    onItemUnFocus:function(id,index ){},
    
    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onFocus: function (id, router) {

        var p = router.callmodule._pageInfo;
        router.callmodule.onItemFocus(id, p.dataOffset + p.viewIndex);
 
    },
    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onUnFocus: function (id, router) {

        var p = router.callmodule._pageInfo;
        router.callmodule.onItemUnFocus(id, p.dataOffset + p.viewIndex);

    },

    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onSelect: function (id, router) {

        var p = router.callmodule._pageInfo;
        router.callmodule.onItemSelect(id, p.dataOffset + p.viewIndex);

    }

};
/**  ListView     */
/**
 * 
 *  用于显示数据表格的基础类
 * 
 *  在外部使用的时候，继承这个基类， create, update 
 *  外部配置Route和布局信息， 会返回调用下面回调函数：
 *  onRender : 在外部函数中处理数据渲染的问题，在更新数据，或者需要翻页的时候，会调用本函数
 *  onItemFocus/onItemUnFocus/onItemSelected :  返回焦点对象ID还有对应的数据索引index , 使用时不用考虑内部的各种事件，或者数据分区问题 
 *  内部数据说明： 
 *  _pageInfo 对象下面
 *    _gridColumns : 5,         //ListView 要显示的列
 *    _currentShowLine : 0,     //当前显示的行， 从0开始 < _gridRows
 *    _currentOffset : 0,       //当前显示的列， 从0开始 < _gridColumns 
 *    _currentPageRowsIndex  : 0,    //当前显示页面起始行索引 
 *    _data : null,             //总的数据缓冲区
 *    _dataTotalRows : 1 ,      //总的行数
 *    _dataFrom :  0,           //当前数据显示开始索引  p._gridColumns * p._currentPageRowsIndex;
 */

 //todo  onRender 回调中，可以加上isFirst ,isLast 来标识是否最后，最末位置，供在外面使用

function ListView() {
    this.name = 'ListView';
    var _html_ = '';
    this._haveCreate = false;
 
    //路由信息
    var _routes = {};
    var groups = {'root': {}};
    this.router = null;

};
ListView.prototype = {
    constructor: ListView,
    _currentFocusId : '',
    _haveCreate :false,
    
    define : function (opt) {
        ListView.call(this, opt); //this是个对象
        if (opt) {
            for (var property in opt) {
                this[property] = opt[property];
            }
        }

    },

    focus :function (id) {
       $g.getFocusRouter(this.name).focus(id);
    },

    _go: function (key) {

        var p = this._pageInfo;
        var r =  $g.getFocusRouter(this.name);

        var focuseObj = null;
        switch (key) {
            case  $g.KeyCodes['ENTER']:
                //this._onSelect(selectObj);
                r.go(key);

                break;

            case $g.KeyCodes['LEFT']:
                if (p._currentOffset == 0) {
                    //超出处理范围，交给系统来完成
                    return r.go(key);
                } else {
                    p._currentOffset = p._currentOffset - 1;
                    return r.go(key);
                }
                break;

            case $g.KeyCodes['RIGHT']:
                if (p._currentOffset >= p._gridColumns) {
                   return r.go(key);
                } else {
                    p._currentOffset = p._currentOffset + 1; 
                    return r.go(key);

                }
                break;

            case $g.KeyCodes['UP']:

                if (p._currentShowLine == 0 && p._currentPageRowsIndex == 0 ) {
                    //跳出
                    return  r.go(key);

                }else if (p._currentShowLine == 0 && p._currentPageRowsIndex > 0 ) {

                    //需要翻页
                    console.log('todo  ----------------------   上翻页 。。。。。');
                    p._currentPageRowsIndex  = p._currentPageRowsIndex - 1;
                   // p._currentShowLine = p._currentShowLine -1;
                    //选中焦点位置不变， 数据更新
                    p._dataFrom = p._gridColumns * p._currentPageRowsIndex;
                    
                    this.onRender(1, p._dataFrom)

                } else{

                    //切到上一行
                    p._currentShowLine = p._currentShowLine -1;
                    return r.go(key);
                }

                break;
            case $g.KeyCodes['DOWN']:

                //当前选中了最后一行，到了数据缓冲区的尾部
                if (p._currentShowLine +1 >= p._gridRows && (p._currentPageRowsIndex + p._gridRows >= p._dataTotalRows) ) {
                    return  r.go(key);
                } else if (p._currentShowLine +1 >= p._gridRows && (p._currentPageRowsIndex + p._gridRows +1 < p._dataTotalRows) ) {
                    console.log('todo  ----------------------   下翻页 。。。。。');
                    //选中焦点位置不变， 数据更新
                    p._currentPageRowsIndex = p._currentPageRowsIndex + 1;
                    p._dataFrom= p._gridColumns * p._currentPageRowsIndex;
                    this.onRender(2,p._dataFrom);

                } else {
                    p._currentShowLine = p._currentShowLine +1;
                    return  r.go(key);
                }

                break;

        }

    },

    onKeyDown: function (key) {
        //需要根据ListView数据做事件处理，进行翻页，换行等操作
        this._go(key);
    },

    //内部初始化数据
    onLoad: function (data) {

        if(!this._haveCreate){
            console.log('ListView 对象没有创建！');
            return;
        }

        var p = this._pageInfo;
        p._currentShowLine = 0;      //当前显示的行， 从0开始 < _gridRows
        p._currentOffset = 0;       //当前显示的列， 从0开始 < _gridColumns 
        p._currentPageRowsIndex  = 0;    //当前显示页面起始行索引 
        p._data = data;             //总的数据缓冲区
        p._dataFrom = 0;

        if(p._gridColumns === 0 )
            return;
        
        p._dataTotalRows = data.length /p._gridColumns + 1;

        this.onRender(0,0);

    },

    //内部创建对象，主要是事件，回调，基本数据
    //componentName：用于登陆注册事件的对象名称
    //that this 指针
    //rows, columns 显示的数据表格的行数和列数
    onCreate: function (componentName, that, rows,columns ) {

        this.name = componentName;
        //内部要重载处理事件
        this.router = $g.createFocusRouter(componentName, that, true);
        this.router.routes = that._routes;
        //router.groups = this.groups;
        this.router.groups = {root:{}};
        this.router.groups.root.fn = [this._onFocus, this._onUnFocus, this._onSelect];

        this._pageInfo = {
            _gridRows : rows,            //ListView 要显示的行
            _gridColumns : columns,         //ListView 要显示的列
            _currentShowLine : 0,     //当前显示的行， 从0开始 < _gridRows
            _currentOffset : 0,       //当前显示的列， 从0开始 < _gridColumns 
            _currentPageRowsIndex  : 0,    //当前显示页面起始行索引 
            _data : '',             //总的数据缓冲区
            _dataTotalRows : 0 ,      //总的行数
            _dataFrom : 0,

        };

        this._currentFocusId = '';
        this._haveCreate = true;

    },
    /**模块出去的路由处理*/
    onRouteOut: function (myid, otherModule, otherId) {

        /**记住自己从那个id出去的*/
        this._currentFocusId = myid;
    },

    /**其他模块不知道怎么跳入时，就会配置通配符*，由自己来处理*/
    onRouteIn: function (id, otherModule, otherId) {
        //可以设置默认的选中焦点
        $g.getFocusRouter(this.name).focus(this._currentFocusId);

    },

    /** Item 被选中 */
    onItemSelect:function(id,index ){},

    /** Item 被Focus */
    onItemFocus:function(id,index ){},
    
    /** Item 被选中 */
    onItemUnFocus:function(id,index ){},
    
    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onFocus: function (id, router) {

        var p = router.callmodule._pageInfo;
        var index  = p._currentPageRowsIndex + p._currentShowLine * p._gridColumns + p._currentOffset;
        router.callmodule.onItemFocus(id, index);
 
    },
    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onUnFocus: function (id, router) {

        var p = router.callmodule._pageInfo;
        var index  = p._currentPageRowsIndex + p._currentShowLine * p._gridColumns + p._currentOffset;
        router.callmodule.onItemUnFocus(id, index);

    },

    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onSelect: function (id, router) {

        var p = router.callmodule._pageInfo;
        var index  = p._currentPageRowsIndex + p._currentShowLine * p._gridColumns + p._currentOffset;
        router.callmodule.onItemSelect(id, index);

    }

};

//--------------------------    Waterfall  begin ---------------------------------


//todo
//1. 可以为不同焦点对象设置圆角大小
//2. 可滚动条。。。
//3. 可以不同Section区设置快速滚动索引标识 

function Waterfall(strName) {

    var me = this;
    this.name = strName || 'waterfall';
    var _html_ = '';
   // var _currentFocusId = null;
   this._haveCreate = false;

    //第一个可显示较多对象element ID 
    var _firstFocusID = null; 

    this.groups = {
        'root': {}
    };
    this.router = null;
    
    //路由信息
    var _routes = {};

    //和Waterfall相关的数据结构
    this.m = {};

    //瀑布流样式配置库
    //尺寸组合
    //每行： 对应的sectionCode， 本行的类型（caption, grid, roller) , top,left ,widght,height ...
    //每行对应下面items, (top.left , width,height, divID ,class , ...URL )
    this.templateConfigLib = {
        'Z': { rows: 1, captionHeight: 80, vspace: 0, hspace: 30, width: 0, height: 0, columnNum: 5, focusImg: "k_0.png" }, 
        //单行， 单元格相同
         'A': { rows: 1, itemNums: 6, captionHeight: 80, vspace: 14, hspace: 30, width: 176, height: 234, columnNum: 6, focusImg: "kuang3_0.png" }, 
         'B': { rows: 1, itemNums: 3, captionHeight: 80, vspace: 14, hspace: 30, width: 370, height: 165, columnNum: 3, focusImg: "kuang2_0.png" }, 
         'C': { rows: 1, itemNums: 8, captionHeight: 80, vspace: 34, hspace: 30, width: 140, height: 60, columnNum: 8, focusImg: "kuang1_0.png" }, 
         'D': { rows: 1, itemNums: 1, captionHeight: 0, vspace: 14, hspace: 30, width: 1124, height: 148, columnNum: 1, focusImg: "kuang1_0.png" }, 
         //多行，单元格相同， Column为每行的列数 
         'E': { rows: 3, itemNums: 18, captionHeight: 80, vspace: 14, hspace: 30, width: 176, height: 234, columnNum: 6, focusImg: "kuang1_0.png" },

        //多行/自定格式， 单元格尺寸不同,  跨行/跨列 可以Merge到到一起
        //       A1，  B， C1, D, E 
        //       A2，  F,  C2  G1,G2   
        'Y': {
            rows: 2, itemNums: 6, captionHeight: 80, vspace: 14, hspace: 30, width: 176, height: 500, columnNum: 6, focusImg: "kuang1_0.png",
            //每行不同Cell的配置，//第一行配置,按照顺序来编排, seq: 取数据的顺序，从0开始, top /lef 都是相对尺寸，计算含跨行的v/hspace 
            rowCfg: [

                {
                    'A': { seq: 0, top: 20, left: 10, width: 382, height: 482 }, 
                    'B': { seq: 1, top: 20, left: 412, width: 176, height: 234 }, 
                    'C': { seq: 2, top: 20, left: 618, width: 176, height: 234 }, 
                    'D': { seq: 3, top: 20, left: 824, width: 176, height: 482 }, 
                    'E': { seq: 4, top: 20, left: 1030, width: 176, height: 482 }
                },
                {
                    'A': { seq: 0, top: 20, left: 10, width: 382, height: 482 }, 
                    'F': { seq: 5, top: 264, left: 412, width: 382, height: 234 }, 
                    'D': { seq: 3, top: 264, left: 824, width: 176, height: 482 }, 
                    'E': { seq: 4, top: 20, left: 1030, width: 176, height: 482 }
                }

            ]
        },

        'W': {
            rows: 1, captionHeight: 0, vspace: 14, hspace: 30, width: 176, height: 200, columnNum: 2, focusImg: "kuang1_0.png",
            //每行不同Cell的配置，//第一行配置,按照顺序来编排, seq: 取数据的顺序，从0开始, top /lef 都是相对尺寸，计算含跨行的v/hspace 
            rowCfg: [
                { 
                    'A': { seq: 0, top: 20, left: 300, width: 200, height: 100 }, 
                    'B': { seq: 1, top: 20, left: 540, width: 200, height: 100 }, 
                }

            ]
        },


    };

    /**模块出去的路由处理*/
    this.m._currentShowLine = 1;
    this.m._currentShowLineOffset = 0;
    //this.m._top = 60;
    this.m._top = 0;

    //外部DIV的位置信息
    this.m._wrapperTop = 20;
    //this.m._wrapperLeft = 10;
    this.m._wrapperLeft = 0;
    this.m._wrapperWidth = 1080;

    //显示的每个区域
    this.m.sections = {};
    //每个逻辑行
    this.m.lines = [];
    this.m._currentTop = 0;
    //去显示焦点对象
    this.m._movingOffset = 0; //
    //显示的数据
    this.m._data = null;


};

Waterfall.prototype = {

    constructor: Waterfall,
    _currentFocusId : null,
    _currentFocusObject: null,

    define : function (opt) {
        Waterfall.call(this, opt); //this是个对象
        if (opt) {
            for (var property in opt) {
                this[property] = opt[property];
            }
        }
    },

    focus :function (id) {
       $g.getFocusRouter(this.name).focus(id);
     },

    //根据当前位置，方向，查找合适的focusItem
    _findNextFocus: function (sDir) {

        //如果是Left
        if (sDir == 'left') {
            var targetLineOffset = this.m._currentShowLineOffset;
            while (targetLineOffset > 0) {

                targetLineOffset = targetLineOffset - 1;

                if (this.m.lines[this.m._currentShowLine].items[targetLineOffset].focusable == true) {

                    this.m._currentShowLineOffset = targetLineOffset;
                    return this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset];
                }

            }

        }
        if (sDir == 'right') {

            var targetLineOffset = this.m._currentShowLineOffset;

            while (targetLineOffset < this.m.lines[this.m._currentShowLine].items.length) {
                targetLineOffset = targetLineOffset + 1;
                if (this.m.lines[this.m._currentShowLine].items[targetLineOffset].focusable == true) {

                    this.m._currentShowLineOffset = targetLineOffset;
                    return this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset];
                }
            }
        }

        if (sDir == 'up') {

            // 当前选中项的中心X坐标
            var lastFouseX = this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset].left + this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset].width * 0.5;
            var targetLine = this.m._currentShowLine;

            while (targetLine > 0) {
                targetLine = targetLine - 1;
                var minDistance = 9999; //到目标焦点对象的最短距离
                var targetObjIndex = -1; //当前最佳焦点对象索引
                var targetObj;

                for (var i = 0; i < this.m.lines[targetLine].items.length; i++) {
                    targetObj = this.m.lines[targetLine].items[i];

                    if (targetObj.focusable == true) {

                        //如果当前焦点对象所为第一个位置， 则优先选中第一个焦点位置
                        if (this.m._currentShowLineOffset == 0) {
                            targetObjIndex = i;
                            break;
                        }

                        //按照最短距离查找下一个焦点对象
                        if (Math.abs(targetObj.left + targetObj.width * 0.5 - lastFouseX) < minDistance) {
                            minDistance = Math.abs(targetObj.left + targetObj.width * 0.5 - lastFouseX);
                            targetObjIndex = i;
                        }
                    }
                }

                //判断elID 是否相同，如果相同，可能是跨行的焦点， 跳过这个焦点，继续查找
                if (targetObjIndex >= 0 && this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset].elId == this.m.lines[targetLine].items[targetObjIndex].elId)
                    continue;

                //找到了合适的焦点对象
                if (targetObjIndex >= 0) {
                    this.m._currentShowLineOffset = targetObjIndex;
                    this.m._currentShowLine = targetLine;
                    return this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset];

                }

            }

        }

        if (sDir == 'down') {

            // 当前选中项的中心X坐标
            var lastFouseX = this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset].left + this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset].width * 0.5;
            var targetLine = this.m._currentShowLine;

            while (targetLine < this.m.lines.length) {

                targetLine = targetLine + 1;

                var minDistance = 9999; //到目标焦点对象的最短距离
                var targetObjIndex = -1; //当前最佳焦点对象索引
                var targetObj;

                for (var i = 0; i < this.m.lines[targetLine].items.length; i++) {
                    targetObj = this.m.lines[targetLine].items[i];

                    if (targetObj.focusable == true) {

                        //如果当前焦点对象所为第一个位置， 则优先选中第一个焦点位置
                        if (this.m._currentShowLineOffset == 0) {
                            targetObjIndex = i;
                            break;
                        }

                        //按照最短距离查找下一个焦点对象
                        if (Math.abs(targetObj.left + targetObj.width * 0.5 - lastFouseX) < minDistance) {
                            minDistance = Math.abs(targetObj.left + targetObj.width * 0.5 - lastFouseX);
                            targetObjIndex = i;
                        }
                    }
                }

                //判断elID 是否相同，如果相同，可能是跨行的焦点， 跳过这个焦点，继续查找
                if (targetObjIndex >= 0 && this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset].elId == this.m.lines[targetLine].items[targetObjIndex].elId)
                    continue;

                //找到了合适的焦点对象
                if (targetObjIndex >= 0) {
                    this.m._currentShowLineOffset = targetObjIndex;
                    this.m._currentShowLine = targetLine;
                    return this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset];

                }

            }

        }

        return null;

    },

    _go: function (key) {

        var focuseObj = null;
        var r =  $g.getFocusRouter(this.name);
        switch (key) {

            case  $g.KeyCodes['ENTER']:

                var selectObj = this.m.lines[this.m._currentShowLine].items[this.m._currentShowLineOffset];

                this._onSelect(selectObj);

                break;

            case $g.KeyCodes['LEFT']:
                if (this.m._currentShowLineOffset == 0) {
                    //超出处理范围，交给系统来完成
                    r.go(key);
                    return;
                } else {
                    focuseObj = this._findNextFocus('left');
                    if (focuseObj == null) {
                        r.go(key);
                        return;
                    }
                }
                break;

            case $g.KeyCodes['RIGHT']:
                if (this.m._currentShowLineOffset + 1 == this.m.lines[this.m._currentShowLine].items.length) {
                    r.go(key);
                    return;
                } else {
                    focuseObj = this._findNextFocus('right');
                    if (focuseObj == null) {
                        r.go(key);
                        return;
                    }
                }
                break;

            case $g.KeyCodes['UP']:

                if (this.m._currentShowLine == 0) {
                    r.go(key);
                    return;
                } else {
                    focuseObj = this._findNextFocus('up');
                    if (focuseObj == null) {
                        r.go(key);
                        return;
                    }
                }
                this.m._top = Math.min(200 - focuseObj.top,0);

                // if (this.m._top > 60)
                //     this.m._top = 60;
                this.m._top = Math.max(720-this.m._currentTop,this.m._top);
                this.m._top = Math.min(0,this.m._top);
                break;
            case $g.KeyCodes['DOWN']:


                if (this.m._currentShowLine + 1 == this.m.lines.length) {
                    return r.go(key);;
                } else {


                    focuseObj = this._findNextFocus('down');
                    if (focuseObj == null) {
                        return r.go(key);;
                    }
                }
                if(focuseObj.top + focuseObj.height + this.m._top > 720){//超出屏幕了
                    this.m._top = -focuseObj.top + 200;//200应该是偏离值,200应该变成可配置的
                    
                }
                this.m._top = Math.max(720-this.m._currentTop,this.m._top);
                this.m._top = Math.min(0,this.m._top);
                break;

        }
        //显示焦点框
        this._flyToFocusItem(focuseObj);

    },

    _flyToFocusItem: function (focuseObj) {
        if (focuseObj == null)
            return;
        //记录位置

        console.dir(focuseObj);
        this.onItemFocus(focuseObj.elId,focuseObj.line,focuseObj.offset,focuseObj.data);

        if(this._currentFocusObejct != undefined)
            this.onItemUnFocus(this._currentFocusObejct.elId,this._currentFocusObejct.line, this._currentFocusObejct.offset, this._currentFocusObejct.data);

        this._currentFocusId = focuseObj.elId;
        this._currentFocusObejct = focuseObj;

        //cjn todo 

        $dom.id(this.router.focusDivId).style.left = (focuseObj.left + this.left_offset - 4) + "px";
        $dom.id(this.router.focusDivId).style.top = (focuseObj.top + this.m._top - 4) + "px";
        $dom.id(this.router.focusDivId).style.width = (focuseObj.width + 4) + "px";
        $dom.id(this.router.focusDivId).style.height = (focuseObj.height + 4) + "px";

        $dom.id(this.router.focusDivId).style.borderRadius = "16px";
        $dom.id(this.scrollElementId || 'waterfall').style.top = this.m._top + 'px';

    },

    //跳转到指定行
    scrollToLine: function (posCode) {

        //首先将页面焦点切换到当前模板中
        $g.getFocusRouter(this.m.name).focus('waterfall_default_btn');


        for (var i = 0; i < this.m.lines.length; i++) {

            for (var j = 0; j < this.m.lines[i].items.length; j++) {


                if (this.m.lines[i].items[j].focusable == true && this.m.lines[i].position == posCode) {

                    this._currentFocusId = this.m.lines[i].items[j].elId;
                    this.m._currentShowLine = i;
                    this.m._currentShowLineOffset = j;
                    return this.m._flyToFocusItem(this.m.lines[i].items[j]);

                }
            }

        }

        //容错处理，跳转到首个位置
        scrollTo('');

    },

    //跳转到指定位置（
    scrollTo: function (elId) {
        //首先将页面焦点切换到当前模板中

        //cjn todo 
        //$g.getFocusRouter(name).focus('waterfall_default_btn');
        $g.getFocusRouter(this.name).focus('waterfall_default_btn');

        //this.m._top = 60;
        this.m._top = 0;

        for (var i = 0; i < this.m.lines.length; i++) {

            for (var j = 0; j < this.m.lines[i].items.length; j++) {

                if (this.m.lines[i].items[j].focusable == true) {

                    if (elId === '' || this.m.lines[i].items[j].elId == elId) {

                        this._currentFocusId = this.m.lines[i].items[j].elId;
                        this.m._currentShowLine = i;
                        this.m._currentShowLineOffset = j;

                        return this._flyToFocusItem(this.m.lines[i].items[j]);

                    }

                }
            }

        }

    },

    //跳转到指定位置
    //line, offset 
    scrollTo2222: function (l, o) {

        console.log('waterfall 还未实现');
        return this.scrollTo('');

        //首先将页面焦点切换到当前模板中

        //cjn todo 
        //$g.getFocusRouter(name).focus('waterfall_default_btn');
        $g.getFocusRouter(this.name).focus('waterfall_default_btn');

        this.m._top = 60;

        if (l >= this.m.lines.length || l < 0)
            return this.scrollTo('');

        if (o >= this.m.lines[l].items.length || o < 0)
            return this.scrollTo('');


        this._currentFocusId = this.m.lines[l].items[o].elId;
        this.m._currentShowLine = l;
        this.m._currentShowLineOffset = o;

        return this._flyToFocusItem(this.m.lines[l].items[o]);

        

    },


    /*------------------------------------------------------------------------------------ */
    //将section/Caption信息添加到lines中
    _addTextline: function (section, top, left, w, h, title, imgUrl) {

        var line = {};
        line.sectionCode = section.code;
        line.sectionElId = section.elId;
        line.top = section.top;
        line.left = section.left;
        line.elId = section.elId + '_cap'
        line.items = [];
        line.type = 'title'; // title 行 

        line.items[0] = {
            "type": 'txt',
            "title": title,
            "top": top,
            "left": left,
            "width": w,
            "height": h,
            "elId": section.elId + '_title',
            focusable: false
        };

        this.m.lines.push(line);
        return this.m.lines.length - 1;

    },

    //添加行头    
    _addLineHeader: function (section) {

        var line = {};

        line.sectionCode = section.code;
        line.sectionElId = section.elId;

        line.sectionPosition = section.position;
        line.elId = section.elId + '_div'
        line.items = [];
        line.type = 'data'; // 数据行 

        this.m.lines.push(line);

        return this.m.lines.length - 1;

    },

    //添加不同的推荐位区域，
    //lineIndex 不同行位置， lineOffset为行内的偏移量
    //如果一个推荐位占了两行，就调用下面两次，在两行添加数据
    _addLineOne: function (section, lineIndex, lineOffset, top, left, w, h, data) {

        if(!data){
            data = {};
        }
        this.m.lines[lineIndex].items[lineOffset] = {
            "line": lineIndex,
            "offset": lineOffset,
            "sectionCode": section.code,
            "type": 'img',
            "title": data.title,
            "img": data.img||data.image1,
            "url": data.url,
            "top": top,
            "left": left,
            "width": w,
            "height": h,
            // "elId": section.elId + '_'+ lineIndex + '_'+ lineOffset + '_img_' + data.seq,
            "elId": section.elId + '_img_' + data.seq,
            "data": data,
            focusable: true
        };
    },


    //根据推荐数据，生成m.sections, m.lines 数据对象
    _prepare: function () {

        var that = this;

        //this.m._currentTop = 50;

        //针对每个推荐区域配配置数据

        for (var i = 0, len = this.m._data.length; i < len; i++) {

            var mSection = {};

            mSection.type = this.m._data[i].type||this.m._data[i].style;
            mSection.top = this.m._currentTop;

            mSection.seq = i;
            mSection.code = this.m._data[i].code;
            mSection.elId = 'section_' + (i + 1);


            mSection.postion = this.m._data[i].position;


            // m._wrapperLeft = ($dom.id('waterfall').style.left).slice(0,-2);

            var templateType = this.m._data[i].type||this.m._data[i].style;
            var templateConfig = this.templateConfigLib[templateType];
            templateConfig.left = templateConfig.left || 0;
            if (templateConfig == null)
                continue;

            //单行，单元格均分
            if (0 == templateType.indexOf("A") || 0 == templateType.indexOf("B") || 0 == templateType.indexOf("C") || 0 == templateType.indexOf("D")) {

                // templateConfig -》 'A': {captionHeight: 50, vspace: 14, hspace: 30, width: 176, height: 234, columnNum: 6, focusImg: "kuang3_0.png"},//组合C
                mSection.left = this.m._wrapperLeft+templateConfig.left;
                //mSection.width = this.m._wrapperWidth;

                if (templateConfig.captionHeight != undefined & templateConfig.captionHeight > 0) {

                    mSection.width = 1200;
                    mSection.height = templateConfig.captionHeight;
                    //添加section Caption内容 top, left, w, h
                    this._addTextline(mSection, this.m._currentTop, this.m._wrapperLeft+templateConfig.left, this.m._wrapperWidth, templateConfig.captionHeight, this.m._data[i].title, '');
                    this.m._currentTop = this.m._currentTop + templateConfig.captionHeight + templateConfig.hspace - 20;
                }

                //添加行头    
                var lineIndex = this._addLineHeader(mSection);

                //按照顺序添加各个items
                var itemNums = this.m._data[i].items ? this.m._data[i].items.length : this.m._data[i].promotions&&this.m._data[i].promotions.length || 0;
                if (itemNums < templateConfig.itemNums) {
                    console.log('数据少!')
                }

                //A样式，有6个Item
                var l = mSection.left;

                for (var j = 0; j < templateConfig.columnNum && j < itemNums; j++) {

                    if (j < itemNums)
                        this._addLineOne(mSection, lineIndex, j, this.m._currentTop, l, templateConfig.width, templateConfig.height, this.m._data[i].items[j]);
                    else
                        this._addLineOne(mSection, lineIndex, j, this.m._currentTop, l, templateConfig.width, templateConfig.height, null);

                    l = l + templateConfig.width + templateConfig.hspace;
                }
                this.m._currentTop = this.m._currentTop + (templateConfig.vspace||0) + templateConfig.height;
            }

            //多行，单元格均分
            if (0 == templateType.indexOf("E")) {

                mSection.left = this.m._wrapperLeft+templateConfig.left;
                //mSection.width = this.m._wrapperWidth;

                if (templateConfig.captionHeight != undefined & templateConfig.captionHeight > 0) {

                    mSection.width = 1200;
                    mSection.height = templateConfig.captionHeight;
                    //添加section Caption内容 top, left, w, h
                    this._addTextline(mSection, this.m._currentTop, this.m._wrapperLeft+templateConfig.left, this.m._wrapperWidth, templateConfig.captionHeight, this.m._data[i].title, '');
                    this.m._currentTop = this.m._currentTop + templateConfig.captionHeight + templateConfig.hspace;
                }

                //按照顺序添加各个items
                var itemNums = this.m._data[i].items.length;

                if (itemNums < templateConfig.itemNums) {
                    console.log('数据少!')
                }


                //添加行头    
                // var lineIndex = this.m._addLineHeader(mSection);
                var lineIndex;

                //E样式，3* 6个Item
                var l = mSection.left;
                var jj = 0;
                for (var j = 0; j < templateConfig.columnNum * templateConfig.rows && j < itemNums; j++) {


                    //要换行了
                    if (j != 0 && (j % templateConfig.columnNum == 0)) {

                        lineIndex = this._addLineHeader(mSection)
                        l = mSection.left;
                        this.m._currentTop = this.m._currentTop + templateConfig.hspace + templateConfig.height;
                        jj = 0;
                    }

                    this._addLineOne(mSection, lineIndex, jj, this.m._currentTop, l, templateConfig.width, templateConfig.height, this.m._data[i].items[j]);
                    jj = jj + 1;
                    l = l + templateConfig.width + templateConfig.vspace;


                }
                this.m._currentTop = this.m._currentTop + (templateConfig.hspace||0) + templateConfig.height;

            }

            //多行，不同单元格自定义
            if (0 == templateType.indexOf("Y") || 0 == templateType.indexOf("W")) {

                mSection.left = this.m._wrapperLeft+templateConfig.left;
                //mSection.width = this.m._wrapperWidth;

                if (templateConfig.captionHeight != undefined & templateConfig.captionHeight > 0) {

                    mSection.width = 1200;
                    mSection.height = templateConfig.captionHeight;
                    //添加section Caption内容 top, left, w, h
                    this._addTextline(mSection, this.m._currentTop, this.m._wrapperLeft+templateConfig.left, this.m._wrapperWidth, templateConfig.captionHeight, this.m._data[i].title, '');
                    this.m._currentTop = this.m._currentTop + templateConfig.captionHeight + (templateConfig.hspace||0);
                }

                //按照顺序添加各个items
                var itemNums = this.m._data[i].items.length;

                //针对这种样式，知道数据元素的多少
                if (itemNums < templateConfig.itemNums) {
                    console.log('数据少!')
                }

                //每行独立处理
                for (var j = 0; j < templateConfig.rowCfg.length; j++) {

                    var lineIndex = this._addLineHeader(mSection);
                    var inx = 0;
                    for (var v in templateConfig.rowCfg[j]) {

                        //创建每个焦点对象信息
                        var cellCfg = templateConfig.rowCfg[j][v];
                        this._addLineOne(mSection, lineIndex, inx, this.m._currentTop + cellCfg.top, mSection.left + cellCfg.left, cellCfg.width, cellCfg.height, this.m._data[i].items[cellCfg.seq]);

                        inx++;

                    }

                }

                this.m._currentTop = this.m._currentTop + (templateConfig.hspace||0) + templateConfig.height;

            }

            //添加滚动区域section
            this.m.sections[mSection.code] = mSection;
        }
    },

    //根据section/lines 数据，生成DOM/HTML
    _render: function () {
        //首先根据section数据，创建各自div
        var parentObj = document.getElementById(this.strWaterfallContainerId || "waterfall");

        //先创建每个sections 区域
        for (var i in this.m.sections) {
            var divNode = document.createElement('div'); //节点div
            divNode.style.position = "absolute";

            divNode.id = this.m.sections[i].elId;
            divNode.style.top = this.m.sections[i].top + 'px';
            divNode.style.left = this.m.sections[i].left + 'px';
            divNode.style.width = this.m.sections[i].width + 'px';
            divNode.style.height = this.m.sections[i].height + 'px';
            divNode.style = 'border:1px solid #F00';
 
            parentObj.appendChild(divNode);

        };

        //针对每个section，添加section下面的item 
        for (var i = 0; i < this.m.lines.length; i++) {

            // console.dir(this.m.lines);

            var parentObj = document.getElementById(this.m.lines[i].sectionElId);

            for (var j = 0; j < this.m.lines[i].items.length && parentObj != null; j++) {
                var divNode;
                if (this.m.lines[i].items[j].type == 'img') {
                    divNode = document.createElement('img'); //节点div
                    //divNode.src = "http://shaoer.gansuyd.joyutech.com:8142" + this.m.lines[i].items[j].img;
                    divNode.src = this.m.lines[i].items[j].img;
                } else {

                    divNode = document.createElement('div'); //节点div
                    divNode.className = 'TextStyle'
                    divNode.innerHTML = '<h2>' + this.m.lines[i].items[j].title + '</h2>';

                }

                //  console.log('render   line = ' + i + '------ pos = ' + j + ' ---- type ' + this.m.lines[i].items[j].type);
                // console.dir( this.m.lines[i].items[j]);

                divNode.style.position = "absolute";
                divNode.style.top = this.m.lines[i].items[j].top + 'px';
                divNode.style.left = this.m.lines[i].items[j].left + 'px';
                divNode.style.width = this.m.lines[i].items[j].width + 'px';
                divNode.style.height = this.m.lines[i].items[j].height + 'px';
                divNode.id = this.m.lines[i].items[j].elId;

                parentObj.appendChild(divNode);

            }


        };
    },
    _initPage: function () {
        //根据数据，生成Line/section数据
        this._prepare();
        //根据Line/section数据生成DOM element 并渲染数据
        this._render();
       // this.scrollTo('');
    },


    /******************    函数部分 **************************/
    onKeyDown: function (key) {

        this._go(key);

    },


    onLoad: function () {

        console.log('load  module  -------  ' + this.name)

        if (!this._haveCreate)
            onCreate();

        this._currentFocusId = '';
        this.m._currentShowLine = 1;
        this.m._currentShowLineOffset = 0;
        //this.m._data = data;

        var that = this;
        if (this.haveCreate) {
            this._initPage();

        } else {
            this.onCreate();

            /**由于本模块有DOM 操作,并且其后立马使用$dom.id()去控制，需要留出cpu时间给渲染线程*/
            setTimeout(function () {
                that._initPage();
            }, 50);
        }


    },

    onCreate: function (comName,that) {

        if (this._haveCreate)
            return;

        console.log('waterfall  onCreate -------------------------------')
        this.name = comName;

        this.router = $g.createFocusRouter(comName, that,true);
        this.router.routes = this._routes;
        this.router.groups = this.groups;
        this.router.groups.root.fn = [this._onFocus, this._onUnFocus, this._onSelect];

        this.router.focus('waterfall_default_btn');
        //$g.getFocusRouter('waterfall').focus('waterfall_default_btn');

        this._haveCreate = true;
        this.scrollElementId = that.scrollElementId;
        this.strWaterfallContainerId = that.strWaterfallContainerId;

    },

    setFocusDiv : function(strId){
        this.router.focusDivId = strId;//为了焦点个性化
    },

    /**模块出去的路由处理*/
    onRouteOut: function (myid, otherModule, otherId) {
        /**记住自己从那个id出去的*/
        otherModule._currentFocusId = myid;
    },

    /**其他模块不知道怎么跳入时，就会配置通配符*，由自己来处理*/
    onRouteIn: function (id, otherModule, otherId) {
        //可以设置默认的选中焦点

        //router.focus( _currentFocusId );
        console.log('onRouteIn  current = ' + this.name);
    
        //router = $g.getFocusRouter(name);

        this.router.focus('waterfall_default_btn');

        //到上次指定的位置
        scrollTo(otherModule._currentFocusId);

    },

    /** Item 被选中 */
    onItemSelect:function(id,line,offset, item ){},

    /** Item 被Focus */
    onItemFocus:function(id,line,offset, item  ){},
        
    /** Item 被选中 */
    onItemUnFocus:function(id,line,offset, item ){},
    

    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onFocus: function (id, router) {

    },
    /**注意，this是router，而不是本实例，需要router.callmodule才是本实例*/
    _onUnFocus: function (id, router) {
        var that = router.callmodule; //实际就是this

    },

    /** 选中 */
    _onSelect: function (obj) {

     //   console.dir(item);
        this.onItemSelect(obj.elId,obj.line,obj.offset,obj.data);

    }


};
//--------------------------   Waterfall  end  -------------------------------------


